//
// Created by youkn on 25-4-7.
//

#ifndef SSUTIL_H
#define SSUTIL_H
#include <codecvt>
#include <locale>
#include <string>
#include <windows.h>
#include <fstream>
#include <QString>
#include <opencv2/opencv.hpp>

#include "SSPoint.h"

namespace SS {
    class SSUtil {
    public:
        static std::string wchar_tToString(const wchar_t* wstr) {
            std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
            return converter.to_bytes(wstr);
        }

        static bool CaptureWindow(HWND hwnd, const char* filename) {
            RECT rect;
            if (!GetWindowRect(hwnd, &rect)) {
                return false;
            }

            int width = rect.right - rect.left;
            int height = rect.bottom - rect.top;

            HDC hdcScreen = GetDC(NULL);
            HDC hdcMemDC = CreateCompatibleDC(hdcScreen);

            HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, width, height);
            SelectObject(hdcMemDC, hBitmap);

            PrintWindow(hwnd, hdcMemDC, 0);

            bool result = SaveBitmapToFile(hBitmap, filename);

            DeleteObject(hBitmap);
            DeleteDC(hdcMemDC);
            ReleaseDC(NULL, hdcScreen);

            return result;
        }
        // 查找小图片在大图片中的位置
        static cv::Point findTemplate(const cv::Mat& largeImage, const cv::Mat& smallImage) {
            cv::Mat result;
            int result_cols = largeImage.cols - smallImage.cols + 1;
            int result_rows = largeImage.rows - smallImage.rows + 1;
            result.create(result_rows, result_cols, CV_32FC1);

            // 进行模板匹配
            cv::matchTemplate(largeImage, smallImage, result, cv::TM_CCOEFF_NORMED);

            // 查找匹配结果中的最大值和最小值及其位置
            double minVal, maxVal;
            cv::Point minLoc, maxLoc;
            cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);

            // 定义匹配阈值
            double threshold = 0.8;
            if (maxVal >= threshold) {
                return maxLoc;
            }
            return cv::Point(0, 0);
        }
        /**
         *
         * @param source 截图
         * @param target 小图片
         * @return 小图片在截图的位置
         */
        static SS::Point getPicturePoint(QString source, QString target) {
            cv::Mat largeImage = cv::imread(source.toStdString(), cv::IMREAD_COLOR);
            cv::Mat smallImage = cv::imread(target.toStdString(), cv::IMREAD_COLOR);

            // 使用 TM_CCOEFF_NORMED 方法时，最大值对应的位置就是最佳匹配位置
            cv::Point matchLoc = findTemplate(largeImage, smallImage);;
            SS::Point pointResult;
            pointResult.x = matchLoc.x;
            pointResult.y = matchLoc.y;
            if (pointResult.x == 0 && pointResult.y == 0) {
                pointResult.isMatching = false;
            } else {
                pointResult.isMatching = true;
            }
            return pointResult;
        }

        static SS::Point getWindowPosition(HWND hwnd) {
            SS::Point res {0,0};
            // 获取窗口的矩形信息
            RECT rect;
            if (!GetWindowRect(hwnd, &rect)) {
                std::cerr << "无法获取窗口位置。" << std::endl;
                return res;
            }
            res.x = rect.left;
            res.y = rect.top;
            return res;
        }
    private:
        // 保存位图到文件
        static bool SaveBitmapToFile(HBITMAP hBitmap, const char* filename) {
            HDC hdcScreen = GetDC(NULL);
            HDC hdcMemDC = CreateCompatibleDC(hdcScreen);
            SelectObject(hdcMemDC, hBitmap);

            BITMAP bmp;
            GetObject(hBitmap, sizeof(BITMAP), &bmp);

            BITMAPINFOHEADER bi;
            bi.biSize = sizeof(BITMAPINFOHEADER);
            bi.biWidth = bmp.bmWidth;
            bi.biHeight = -bmp.bmHeight;
            bi.biPlanes = 1;
            bi.biBitCount = 32;
            bi.biCompression = BI_RGB;
            bi.biSizeImage = 0;
            bi.biXPelsPerMeter = 0;
            bi.biYPelsPerMeter = 0;
            bi.biClrUsed = 0;
            bi.biClrImportant = 0;

            DWORD dwBmpSize = ((bmp.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmp.bmHeight;

            char* lpbitmap = new char[dwBmpSize];
            GetDIBits(hdcMemDC, hBitmap, 0, (UINT)bmp.bmHeight, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS);

            BITMAPFILEHEADER bmfHeader;
            bmfHeader.bfType = 0x4D42;
            DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
            bmfHeader.bfSize = dwSizeofDIB;
            bmfHeader.bfReserved1 = 0;
            bmfHeader.bfReserved2 = 0;
            bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

            std::ofstream file(filename, std::ios::binary);
            if (!file) {
                delete[] lpbitmap;
                DeleteDC(hdcMemDC);
                ReleaseDC(NULL, hdcScreen);
                return false;
            }

            file.write((const char*)&bmfHeader, sizeof(BITMAPFILEHEADER));
            file.write((const char*)&bi, sizeof(BITMAPINFOHEADER));
            file.write(lpbitmap, dwBmpSize);
            file.close();

            delete[] lpbitmap;
            DeleteDC(hdcMemDC);
            ReleaseDC(NULL, hdcScreen);
            return true;
        }
    };
}




#endif //SSUTIL_H
